# -*- coding: utf_8 -*-
import json
import logging

import modbus_tk
import modbus_tk.defines as cst
import modbus_tk.modbus_tcp as modbus_tcp
import time
import redis

logger = modbus_tk.utils.create_logger("console")
logger.setLevel(logging.INFO)

# 该程序应该每指定时间执行一次如500ms
# ip号在前面的是前10个设备，以此类推
redis_pool = redis.ConnectionPool(host='reform-redis', port=6379)
ips = ["172.6.2.75", "172.6.2.76"]
DEVICE_NUM_PER_MASTER = 10
devices = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
while True:
    status_read = [{"device": i} for i in devices]

    try:
        # only use holding registers
        # 连接MODBUS TCP从机
        for master_index, ip in enumerate(ips):
            logger.debug("connecting")
            master = modbus_tcp.TcpMaster(host=ip)
            # 另一台从机的ip地址为172.6.2.76,将来ip地址写到配置文件里
            master.set_timeout(0.5)
            logger.debug("connected")
            # 读保持寄存器
            # 后两个参数分别表示offset和limit
            # pwm存在offset为0,30,60……270处,由后端写入
            # 负载电压电流存在offset为1,31,61……271处,由后端读取,数据格式为:电压小数点位,X,电压值,X,X,X,X,X,电流(ma)
            # 太阳能电池板电压电流存在offset为1,31,61……271处,由后端读取,数据格式为:电压小数点位,X,电压值,X,X,X,X,X,电流(ma)
            # 电压计算格式为 电压(mv) = 电压值 * 10**(int(小数点位/256)-1)
            pwm_offset = [0, 30, 60, 90, 120, 150, 180, 210, 240, 270]
            payload_offset = [1, 31, 61, 91, 121, 151, 181, 211, 241, 271]
            generator_offset = [11, 41, 71, 101, 131, 161, 191, 221, 251, 281]
            for index, offset in enumerate(pwm_offset):
                # 写pwm
                r = redis.Redis(connection_pool=redis_pool)

                pwm = r.get("reform.pwm.{}".format(DEVICE_NUM_PER_MASTER * master_index + index + 1))
                if pwm:
                    pwm = int(pwm)
                else:
                    pwm = 0
                logger.debug(master.execute(1, cst.WRITE_SINGLE_REGISTER, starting_address=offset,
                                            output_value=pwm))

            for index, offset in enumerate(payload_offset):
                data = master.execute(1, cst.READ_HOLDING_REGISTERS, starting_address=offset, quantity_of_x=9)

                # 电压小数点位
                u_decimals_tmp = data[0]
                logger.debug("payload offset:{} u_decimals_tmp:{}".format(offset, u_decimals_tmp))

                # 电压值
                u_tmp = data[2]
                logger.debug("payload offset:{} u_tmp:{}".format(offset, u_tmp))

                u = u_tmp * 10 ** (int(u_decimals_tmp / 256) - 1)

                logger.debug("payload offset:{} u:{}".format(offset, u))

                # 电流值
                i = data[8]
                logger.debug("payload offset:{} i:{}".format(offset, i))

                status_read[DEVICE_NUM_PER_MASTER * master_index + index]["payload_i"] = i
                status_read[DEVICE_NUM_PER_MASTER * master_index + index]["payload_u"] = u

            for index, offset in enumerate(generator_offset):
                data = master.execute(1, cst.READ_HOLDING_REGISTERS, starting_address=offset, quantity_of_x=9)

                # 电压小数点位
                u_decimals_tmp = data[0]
                logger.debug("generator offset:{} u_decimals_tmp:{}".format(offset, u_decimals_tmp))

                # 电压值
                u_tmp = data[2]
                logger.debug("generator offset:{} u_tmp:{}".format(offset, u_tmp))

                u = u_tmp * 10 ** (int(u_decimals_tmp / 256) - 1)

                logger.debug("generator offset:{} u:{}".format(offset, u))

                # 电流值
                i = data[8]
                logger.debug("generator offset:{} i:{}".format(offset, i))

                status_read[DEVICE_NUM_PER_MASTER * master_index + index]["generator_i"] = i
                status_read[DEVICE_NUM_PER_MASTER * master_index + index]["generator_u"] = u
    except modbus_tk.modbus.ModbusError, e:
        logger.error("%s- Code=%d" % (e, e.get_exception_code()))
    except Exception, e:
        logger.error(str(e))

    try:
        # 输出结果
        # 如果某台主机故障，造成DEVICE_NUM_PER_MASTER个设备读不到数据，则这DEVICE_NUM_PER_MASTER个数据的仅显示device号 例如 {'device': 11}
        logger.info(status_read)
        r = redis.Redis(connection_pool=redis_pool)
        r.set("reform.status_read", json.dumps(status_read), ex=30)
    except Exception, e:
        logger.error(str(e))
    finally:
        time.sleep(0.5)
